//
//  HZJChartView.swift
//  HZJChart
//
//  Created by HZJ on 17/1/13.
//  Copyright © 2017年 HZJ. All rights reserved.
//

import UIKit
// FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
// Consider refactoring the code to use the non-optional operators.
fileprivate func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return l < r
  case (nil, _?):
    return true
  default:
    return false
  }
}

// FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
// Consider refactoring the code to use the non-optional operators.
fileprivate func > <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return l > r
  default:
    return rhs < lhs
  }
}


class HZJChartView: UIView {
    
    ///数据线条 实线 的颜色
    var lineColor:UIColor = UIColor.randomColor()
    ///数据线条 虚线 的颜色
    var dottedColor:UIColor = UIColor.randomColor()
    ///图形线条下方阴影渐变颜色
    var fillBottomColor:UIColor  = UIColor.white
    ///各个点描述处的背景色
    var labBgColor:UIColor = UIColor.randomColor()
    ///各个点的颜色
    var pointColor:UIColor = UIColor.randomColor()
    ///各个点的填充色
    var pointFillColor:UIColor = UIColor.randomColor()
    
    ///水平坐标文字颜色
    var theTitleColor:UIColor = UIColor.gray
    ///水平坐标文字字体
    var theTitleFont:UIFont = UIFont.systemFont(ofSize: 10.0)
    ///是否绘制水平坐标上各个点的文字描述
    var isDrawPointText:Bool = true
    ///图像距左右边的距离
    var distanceH:CGFloat = 0
    ///图像距上下边的距离
    var distanceV:CGFloat = 0
    ///图表数据
    var charData = [NSString:NSNumber]() {
        didSet{
            titleArray = (charData as NSDictionary).allKeys as! [NSString]
            dataArray = (charData as NSDictionary).allValues as! [NSNumber]
        }
    }
    
    //MARK: - 私有参数
    
    fileprivate var dataArray:[NSNumber]!
    fileprivate var titleArray:[NSString]!
    fileprivate var min:CGFloat!
    fileprivate var max:CGFloat!
    
    //下部图像数据的宽
    fileprivate var axisWidth:CGFloat!{
        return axisView.frame.size.width - 2 * distanceH
    }
    //下部图像数据的高
    fileprivate var axisHeight:CGFloat {
        return axisView.frame.size.height - 4.5 * distanceV
    }
    
    
    //MARK: - 方法（公共）
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setUpUI()
    }
    override func awakeFromNib() {
        super.awakeFromNib()
        setUpUI()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setUpUI()
    }

    /**
     *绘制线段图像（阴影无渐变色）
     *hasAnimation: 是否有动画效果
     */
    func setLineChart(_ hasAnimation:Bool){
        
        min = CGFloat(MAXFLOAT)
        max = CGFloat(-MAXFLOAT)
        for i:Int in 0 ..< dataArray.count {
            let number:NSNumber = dataArray[i]
            
            if CGFloat(number.floatValue) < min  {
                min = CGFloat(number.floatValue)
            }
            if CGFloat(number.floatValue) > max {
                max = CGFloat(number.floatValue)
            }
        }
        if max.isNaN || max == 0{
            max = 1
        }
        strokeChart(hasAnimation)
        
//        strokeLabH()
        
    }
    
    //MARK: - 方法（私有）
    
    /**
    *设置基础UI
    */
    fileprivate func setUpUI() {
        self.backgroundColor = UIColor.gray
        addSubview(titleLab)
        addSubview(firstLine)
        addSubview(bottomTitleView)
        addSubview(axisView)
        titleLab.frame = CGRect(x: distanceH,y: 0,width: frame.width - 2 * distanceH,height: frame.height * 0.2)
        firstLine.frame = CGRect(x: distanceH, y: titleLab.frame.maxY, width: frame.width - 2 * distanceH, height: 0.5)
        bottomTitleView.frame = CGRect(x: 0,y: frame.height - 60,width: frame.width,height: 60)
        axisView.frame = CGRect(x: 0,y: firstLine.frame.maxY,width: frame.width,height: bottomTitleView.frame.minY - firstLine.frame.maxY)
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        titleLab.frame = CGRect(x: distanceH,y: 0,width: frame.width - 2 * distanceH,height: frame.height * 0.2)
        firstLine.frame = CGRect(x: distanceH, y: titleLab.frame.maxY, width: frame.width - 2 * distanceH, height: 0.5)
        bottomTitleView.frame = CGRect(x: 0,y: frame.height - 60,width: frame.width,height: 60)
        axisView.frame = CGRect(x: 0,y: firstLine.frame.maxY,width: frame.width,height: bottomTitleView.frame.minY - firstLine.frame.maxY)
    }
    
    /**
     *绘制水平坐标轴上的标签
     */
    fileprivate func strokeLabH(){
        //清除先前所绘制坐标轴上的标签
        bottomTitleView.layer.sublayers?.removeAll()
        
        for i in 0  ..< 3 {
            let text = titleArray[i * 12]
            let label = UILabel(frame: CGRect(x: CGFloat(i) * (bottomTitleView.frame.width / 3), y: 0, width: bottomTitleView.frame.width / 3, height: 30))
            label.text = text as String
            label.font = theTitleFont
            label.textColor = theTitleColor
            if i == 0 {
                label.textAlignment = .left
            }
            else if i == 1 {
                label.textAlignment = .center
            }
            else if i == 2 {
                label.textAlignment = .right
            }
            bottomTitleView.addSubview(label)
        }
        //        if data.count > 1 {
        //            for var i:Int = 0 ; i < data.count; i++ {
        //                let text = titleData.objectAtIndex(i) as! String
        //                let label = UILabel(frame: CGRectMake(0, 0, self.frame.size.width * 0.25, 30))
        //                label.center = CGPointMake(CGFloat(i) * (axisWidth / CGFloat(data.count - 1)) + distanceH,15)
        //                label.text = text
        //                label.font = theTitleFont
        //                label.textColor = theTitleColor
        //                label.textAlignment = .Center
        //                bottomTitleView.addSubview(label)
        //            }
        //        }
        //        else {
        //            let text = titleData.objectAtIndex(0) as! String
        //            let label = UILabel(frame: CGRectMake(0, 0, self.frame.size.width, 30))
        //            label.text = text
        //            label.font = theTitleFont
        //            label.textColor = theTitleColor
        //            bottomTitleView.addSubview(label)
        //        }
    }
    
    /**
     *绘制数据线
     */
    fileprivate func strokeChart(_ hasAnimation:Bool){
        if dataArray.count == 0 {
            NSLog("Warning: no data provided for the chart")
            return
        }
        //清除先前所绘制视图
        axisView.layer.sublayers?.removeAll()
        
        //Y轴最大值
        let theMaxPointY = axisView.frame.height - distanceV
        
        //实线路径 -动画结束时状态
        let path = UIBezierPath()
        //实线路径 -动画开始时状态
        let noPath = UIBezierPath()
        //虚线路径
        let dottedPath = UIBezierPath()
        //虚线路径
        let noDottedPath = UIBezierPath()
        
        //填充路径 - 动画结束时状态
        let fill = UIBezierPath()
        //填充路径 - 动画开始时状态
        let noFill = UIBezierPath()
        
        //渐变色阴影的轮廓
        var gradientPath = UIBezierPath()
        
        
        let scale = axisHeight / max
        let first = dataArray[0]
        
        let pointsCenterLocations = NSMutableArray()
        let pointsLabelLocations = NSMutableArray()
        if dataArray.count == 1 {
            let p1 = CGPoint(x: distanceH, y: theMaxPointY)
            let p2 = CGPoint(x: frame.width * 0.5, y: theMaxPointY - CGFloat(first.floatValue) * scale)
            let p3 = CGPoint(x: frame.width - distanceH, y: theMaxPointY )
            
            fill.move(to: p1)
            fill.addLine(to: p2)
            fill.addLine(to: p3)
            fill.addLine(to: p1)
            
            noFill.move(to: p1)
            noFill.addLine(to: CGPoint(x: p2.x, y: theMaxPointY))
            noFill.addLine(to: p3)
            noFill.addLine(to: p1)
            
            pointsCenterLocations.add(NSValue(cgPoint: p2))
            
            path.move(to: p1)
            path.addLine(to: p2)
            path.addLine(to: p3)
            
            noPath.move(to: p1)
            noPath.addLine(to: CGPoint(x: p2.x, y: theMaxPointY))
            noPath.addLine(to: p3)
            
        }
        else {
            for i:Int in 1  ..< dataArray.count {
                let last = dataArray[i - 1]
                let number = dataArray[i]
                
                let p1 = CGPoint(x: distanceH + CGFloat(i - 1) * (axisWidth / (CGFloat(dataArray.count) - 1)), y: theMaxPointY - CGFloat(last.floatValue) * scale)
                let p2 = CGPoint(x: distanceH + CGFloat(i) * (axisWidth / (CGFloat(dataArray.count) - 1)), y: theMaxPointY - CGFloat(number.floatValue) * scale)
                if last != 0 {
                    path.move(to: p1)
                    noPath.move(to: CGPoint(x: p1.x, y: theMaxPointY))
                    
                    if dottedPath.isEmpty == false {
                        //当dottedPath已经有点后，才可使用addLineToPoint
                        dottedPath.addLine(to: p1)
                    }
                    if noDottedPath.isEmpty == false {
                        noDottedPath.addLine(to: CGPoint(x: p1.x, y: theMaxPointY))
                    }
                    
                    fill.move(to: p1)
                    
                    noFill.move(to: CGPoint(x: p1.x, y: theMaxPointY))
                    
                    if number != 0 {
                        path.addLine(to: p2)
                        noPath.addLine(to: CGPoint(x: p2.x, y: theMaxPointY))
                        
                        dottedPath.move(to: p2)
                        noDottedPath.move(to: CGPoint(x: p2.x, y: theMaxPointY))
                        
                        
                        fill.addLine(to: p2)
                        fill.addLine(to: CGPoint(x: p2.x, y: theMaxPointY))
                        fill.addLine(to: CGPoint(x: p1.x, y: theMaxPointY))
                        
                        noFill.addLine(to: CGPoint(x: p2.x, y: theMaxPointY))
                        noFill.addLine(to: CGPoint(x: p2.x, y: theMaxPointY))
                        noFill.addLine(to: CGPoint(x: p1.x, y: theMaxPointY))
                        
                    }
                    
                }else {
                    if number != 0 {
                        path.move(to: p2)
                        noPath.move(to: CGPoint(x: p2.x, y: theMaxPointY))
                        if dottedPath.isEmpty == false {
                            //当dottedPath已经有点后，才可使用addLineToPoint
                            dottedPath.addLine(to: p2)
                        }else{
                            dottedPath.move(to: p2)
                        }
                        if noDottedPath.isEmpty == false {
                            noDottedPath.addLine(to: CGPoint(x: p2.x, y: theMaxPointY))
                        }else{
                            noDottedPath.move(to: CGPoint(x: p2.x, y: theMaxPointY))
                            
                        }
                        
                        fill.move(to: p2)
                        
                        noFill.move(to: CGPoint(x: p2.x, y: theMaxPointY))
                    }
                }
                
                gradientPath = fill
                
                var pointValue = NSValue()
                pointValue = NSValue(cgPoint: p2)
                if i == 1 {
                    pointsCenterLocations.add(NSValue(cgPoint: p1))
                }
                pointsCenterLocations.add(pointValue)
                pointsLabelLocations.add(NSValue(cgPoint: p1))
                
                if i == dataArray.count - 1 {
                    pointsLabelLocations.add(NSValue(cgPoint: p2))
                }
            }
            
        }
        
        let fillLayer = CAShapeLayer()
        fillLayer.frame = bounds
        fillLayer.bounds = bounds
        fillLayer.path = fill.cgPath
        fillLayer.strokeColor = nil
        fillLayer.lineWidth = 0
        fillLayer.lineJoin = kCALineJoinRound
        axisView.layer.addSublayer(fillLayer)
        
        //绘制实线
        let pathLayer = CAShapeLayer()
        pathLayer.path = path.cgPath
        pathLayer.strokeColor = lineColor.cgColor
        pathLayer.fillColor = nil
        pathLayer.lineWidth = 1
        pathLayer.lineJoin = kCALineJoinRound
        axisView.layer.addSublayer(pathLayer)
        
        //绘制虚线
        let dottedPathLayer = CAShapeLayer()
        //虚线模式
        dottedPathLayer.lineDashPattern = [4,4]
        dottedPathLayer.path = dottedPath.cgPath
        dottedPathLayer.strokeColor = dottedColor.cgColor
        dottedPathLayer.fillColor = nil
        dottedPathLayer.lineWidth = 1
        dottedPathLayer.lineJoin = kCALineJoinRound
        axisView.layer.addSublayer(dottedPathLayer)
        
        if hasAnimation {
            
            fillLayer.fillColor = fillBottomColor.withAlphaComponent(0.3).cgColor
            //填充动画
            let fillAnimation = CABasicAnimation(keyPath: "path")
            fillAnimation.duration = 0.5
            fillAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
            fillAnimation.fillMode = kCAFillModeForwards
            fillAnimation.fromValue = noFill.cgPath
            fillAnimation.toValue = fill.cgPath
            fillLayer.add(fillAnimation, forKey: "path")
            
            //实现动画
            let pathAnimation = CABasicAnimation(keyPath: "path")
            pathAnimation.duration = 0.5
            pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
            pathAnimation.fromValue = noPath.cgPath
            pathAnimation.toValue = path.cgPath
            pathLayer.add(pathAnimation, forKey: "path")
            //虚线动画
            let dottedPathAnimation = CABasicAnimation(keyPath: "path")
            dottedPathAnimation.duration = 0.5
            dottedPathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
            dottedPathAnimation.fromValue = noDottedPath.cgPath
            dottedPathAnimation.toValue = dottedPath.cgPath
            dottedPathLayer.add(dottedPathAnimation, forKey: "path")
        }else {
            fillLayer.fillColor = UIColor.clear.cgColor
            //绘制渐变色阴影
            let gradientLayer = CAGradientLayer()
            gradientLayer.frame = CGRect(x: 0, y: 0, width: axisView.frame.size.width, height: theMaxPointY)
            gradientLayer.colors = [fillBottomColor.withAlphaComponent(1).cgColor,fillBottomColor.withAlphaComponent(0).cgColor]
            gradientLayer.locations = [0,1]
            gradientLayer.startPoint = CGPoint(x: 0, y: 0)
            gradientLayer.endPoint = CGPoint(x: 0, y: 1)
            
            let gradientPathLayer = CAShapeLayer()
            gradientPathLayer.path = gradientPath.cgPath
            gradientLayer.mask = gradientPathLayer
            self.axisView.layer.addSublayer(gradientLayer)
        }
        
        drawPointswithStrokeColour(pointColor, andFill: pointFillColor, fromArray: pointsCenterLocations, zeroY:theMaxPointY)
        
        if isDrawPointText == true {
            
            for i in 0 ..< pointsLabelLocations.count {
                if (pointsLabelLocations.object(at: i) as AnyObject).cgPointValue.y != theMaxPointY {
                    createPointLabelForPoint((pointsLabelLocations.object(at: i) as AnyObject).cgPointValue, withLabelText:String(format: "%@",dataArray[i] ))
                }
            }
        }
    }
    /**绘制各个点
     *stroke:      各个点的颜色
     *fill:        各个点的中心填充色
     *pointsArray: 所有点中心坐标的集合
     *zeroY:       在视图上的Y轴坐标的相对0值（Y轴最大值）
     */
    fileprivate func drawPointswithStrokeColour(_ stroke:UIColor? ,andFill fill:UIColor? ,fromArray pointsArray:NSMutableArray ,zeroY:CGFloat){
        let pointCenterLocations:NSMutableArray = pointsArray
        for i:Int in 0 ..< pointCenterLocations.count {
            let pointCenter = (pointCenterLocations.object(at: i) as AnyObject).cgPointValue
            if pointCenter?.y != zeroY {
                //不绘制0值得点
//                let pointRect = CGRectMake(0, 0, 8, 8)
//                let point = ChartPoint(frame: pointRect)
//                if stroke != nil {
//                    point.strokeColor = stroke
//                }
//                else {
//                    point.strokeColor = UIColor.redColor()
//                }
//                if fill != nil {
//                    point.fillColor = fill
//                }
//                else {
//                    point.fillColor = UIColor.yellowColor()
//                }
//                point.center = pointCenterLocations.objectAtIndex(i).CGPointValue
//                point.backgroundColor = UIColor.clearColor()
//                self.axisView.addSubview(point)
            }
        }
    }
    
    /**
     *绘制各个点的文字描述
     */
    fileprivate func createPointLabelForPoint(_ point:CGPoint,withLabelText string:String){
        
        let tempLabel:UILabel = UILabel(frame: CGRect(x: point.x , y: point.y, width: 35, height: 20))
        tempLabel.font = UIFont.systemFont(ofSize: 12.0)
        tempLabel.layer.cornerRadius = 10
        tempLabel.layer.masksToBounds = true
        tempLabel.textAlignment = NSTextAlignment.center
        tempLabel.textColor = UIColor.black
        tempLabel.backgroundColor = labBgColor
        tempLabel.adjustsFontSizeToFitWidth = true
        tempLabel.minimumScaleFactor = 0.6
        self.axisView.addSubview(tempLabel)
        tempLabel.center = CGPoint(x: point.x, y: point.y)
        tempLabel.text = string
    }
    
    /**
     *
     */
    fileprivate func getUpperRoundNumber(_ value:CGFloat,forGridStep gridStep:Int)->CGFloat{
        if value == 0 {
            return 1
        }
        let logValue:CGFloat = CGFloat(log10f(Float(value)))
        let scale = CGFloat(powf(10, floorf(Float(logValue))))
        var n = CGFloat(ceilf(CFloat(value / scale * 2)))
        let tmp = Int(n) % gridStep
        
        if tmp != 0 {
            n += CGFloat(gridStep - tmp)
        }
        
        return n * scale / 2.0;
    }
    
    
    
    //MARK: - 懒加载
    ///标题
    fileprivate lazy var titleLab:UILabel = {
        let lab = UILabel()
        lab.font = UIFont.systemFont(ofSize: 16)
        lab.textColor = UIColor.white
        lab.textAlignment = .center
        lab.text = "标题"
        return lab
    }()

    ///第一条分割线
    fileprivate lazy var firstLine:UIView = {
        let v = UIView()
        v.backgroundColor = UIColor.white
        return v
    }()
    ///各个点下面的标题
    fileprivate lazy var bottomTitleView:UIView = {
        let v = UIView()
        v.backgroundColor = UIColor.white
        return v
    }()
    
    ///图片视图(所有视图皆绘制于此之上，以便于再次绘制时删除先前所绘制图像)
    fileprivate lazy var axisView:UIView = {
        let v = UIView()
        v.backgroundColor = UIColor.clear
        return v
    }()
    
}
